package com.xci.platform.auth.service;

import cn.hutool.core.convert.Convert;
import com.xci.platform.annotation.OperateUser;
import com.xci.platform.auth.core.AuthConstant;
import com.xci.platform.auth.core.DicDetailsTreeOperate;
import com.xci.platform.auth.core.HistoryModel;
import com.xci.platform.auth.core.HistoryOperateType;
import com.xci.platform.auth.dao.DicDao;
import com.xci.platform.auth.dao.DicDetailsDao;
import com.xci.platform.auth.entity.DicDetailsEntity;
import com.xci.platform.auth.entity.DicEntity;
import com.xci.platform.core.*;
import com.xci.platform.helper.CoreHelper;
import com.xci.platform.helper.ObjectHelper;
import com.xci.platform.helper.StringHelper;
import com.xci.platform.helper.TreeHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import javax.swing.tree.TreeModel;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 系统字典明细服务
 */
@SuppressWarnings("unchecked")
@Service
public class DicDetailsService extends AuthBaseService {

    /**
     * 字典数据访问对象
     */
    @Resource
    private DicDao dicDao;

    /**
     * 字典明细数据访问对象
     */
    @Resource
    private DicDetailsDao dicDetailsDao;

    /**
     * 获取树形结构操作服务对象
     */
    private TreeOperateService getTreeOperateService(String dicCode) {
        return new TreeOperateService(new DicDetailsTreeOperate(dicCode, dicDetailsDao));
    }

    /**
     * 保存字典明细
     *
     * @param entity   字典明细对象
     * @param isCreate 是否新建
     */
    @Validated
    @OperateUser
    @Transactional(rollbackFor = Exception.class)
    public BoolMessage save(DicDetailsEntity entity, Boolean isCreate) {
        //添加名称简拼
        entity.setSpell(StringHelper.getSpell(entity.getName()));
        //验证父节点
        if (StringHelper.isBlank(entity.getParentId())) {
            entity.setParentId(Constant.RootNodeId);
        }
        //字典明细名称验证
        if (dicDetailsDao.existByName(entity.getName(), entity.getDicId(), entity.getId()) > 0) {
            String msg = StringHelper.format("字典明细名称 {} 已经存在", entity.getName());
            return new BoolMessage<>(false, msg);
        }

        String msg;
        long startTime = CoreHelper.startWatch();
        if (isCreate) {
            DicEntity dicEntity = dicDao.queryById(entity.getDicId());
            entity.setDicCode(dicEntity.getCode());
            entity.setDicName(dicEntity.getName());
            entity.setPath(getTreeOperateService(entity.getDicCode()).buildNewPath(entity.getParentId()));//获取路径
            msg = StringHelper.format("新增字典明细 {}", entity.getName());
            dicDetailsDao.insert(entity);
            //region 历史记录
            operateHistory(buildHistory()
                    .operateType(HistoryOperateType.Insert)
                    .keyValue(entity.getId())
                    .message(msg)
                    .after(entity)
            );
            //endregion
        } else {
            msg = StringHelper.format("修改字典明细 {}", entity.getName());
            DicDetailsEntity oldEntity = queryById(entity.getId());
            dicDetailsDao.update(entity);
            //region 历史记录
            operateHistory(buildHistory()
                    .operateType(HistoryOperateType.Update)
                    .keyValue(entity.getId())
                    .message(msg)
                    .before(oldEntity)
                    .after(entity)
            );
            //endregion
        }
        // 操作日志
        operateLog(AuthConstant.SystemModule.DicDetails, msg, CoreHelper.stopWatch(startTime));
        //更新节点叶子状态
        getTreeOperateService(entity.getDicCode()).updateLeafStatus();
        return BoolMessage.True;
    }

    /**
     * 删除字典明细
     *
     * @param id 字典明细主键
     */
    @Validated
    @Transactional(rollbackFor = Exception.class)
    public BoolMessage delete(@NotEmpty(message = "请指定删除的字典明细主键") String id) {
        DicDetailsEntity currentEntity = dicDetailsDao.queryById(id);
        if (currentEntity == null) return BoolMessage.fail("无效的字典明细主键");

        String dicId = currentEntity.getDicId();
        String dicCode = currentEntity.getDicCode();
        Map params = new HashMap();
        params.put("dicId", dicId);
        List<DicDetailsEntity> childs = (List<DicDetailsEntity>) TreeHelper.getChilds(dicDetailsDao.queryByDic(params), id, true);
        for (DicDetailsEntity entity : childs) {
            long startTime = CoreHelper.startWatch();
            dicDetailsDao.delete(entity.getId());
            String msg = StringHelper.format("删除字典明细 {}", entity.getName());
            //region 历史记录
            operateHistory(buildHistory()
                    .operateType(HistoryOperateType.Delete)
                    .keyValue(entity.getId())
                    .message(msg)
                    .before(entity)
            );
            //endregion
            operateLog(AuthConstant.SystemModule.DicDetails, msg, CoreHelper.stopWatch(startTime)); // 操作日志
        }
        //更新节点叶子状态
        getTreeOperateService(dicCode).updateLeafStatus();
        return BoolMessage.True;
    }

    /**
     * 保存拖拽数据(父节点和路径)
     *
     * @param nodeIndexs 更新的节点数据
     */
    @Transactional(rollbackFor = Exception.class)
    public BoolMessage updateNodeIndex(TreeNodeIndex[] nodeIndexs) {
        if (nodeIndexs.length == 0) {
            return BoolMessage.True;
        }
        DicDetailsEntity currentEntity = dicDetailsDao.queryById(nodeIndexs[0].getId());
        if (currentEntity == null) return BoolMessage.fail("无效的字典明细主键");
        String dicCode = currentEntity.getDicCode();
        TreeOperateService treeOperateService = getTreeOperateService(dicCode);
        treeOperateService.updateParentAndPath(nodeIndexs);
        treeOperateService.rebuildPath(Constant.RootNodeId);
        return BoolMessage.True;
    }

    /**
     * 更新字典明细启用状态
     *
     * @param id     字典明细主键
     * @param status 是否启用(1:启用 0:禁用)
     */
    @Validated
    @Transactional(rollbackFor = Exception.class)
    public BoolMessage updateStatus(@NotNull(message = "请指定更新状态的字典明细主键") String id,
                                    @NotNull(message = "请指定状态") Integer status) {
        long startTime = CoreHelper.startWatch();
        dicDetailsDao.updateStatus(id, status);
        // 操作日志
        String msg = StringHelper.format("更新字典明细状态 主键: {} 更新后状态: {}", id, status);
        operateLog(AuthConstant.SystemModule.DicDetails, msg, CoreHelper.stopWatch(startTime));
        return BoolMessage.True;
    }

    /**
     * 根据主键更新父节点以及排序路径
     *
     * @param dicId   字典主键
     * @param dicCode 字典编码
     * @param dicName 字典名称
     */
    @Transactional(rollbackFor = Exception.class)
    public BoolMessage updateDicCodeAndName(String dicId, String dicCode, String dicName) {
        dicDetailsDao.updateDicCodeAndName(dicId, dicCode, dicName);
        return BoolMessage.True;
    }

    /**
     * 根据字典明细主键获取字典明细对象
     *
     * @param id 字典明细主键
     * @return 返回指定字典明细主键的字典明细对象
     */
    @Validated
    public DicDetailsEntity queryById(@NotNull(message = "请指定字典明细主键") String id) {
        return dicDetailsDao.queryById(id);
    }

    /**
     * 查询字典明细列表
     *
     * @return 返回符合查询条件的字典明细列表
     */
    public List<DicDetailsEntity> query(Map params) {
        if (params == null) params = new HashMap();
        Object nameObj = params.get("name");
        Object statusObj = params.get("status");
        List<DicDetailsEntity> list = dicDetailsDao.queryByDic(params);
        if (ObjectHelper.isBlank(nameObj) && ObjectHelper.isBlank(statusObj)) {
            return list;
        }
        List<DicDetailsEntity> result = list;
        if (ObjectHelper.isNotBlank(nameObj)) {
            String name = nameObj.toString().toLowerCase();
            result = result.stream().filter(p -> p.getName().toLowerCase().contains(name)
                    || (p.getSpell() != null && p.getSpell().toLowerCase().contains(name)))
                    .collect(Collectors.toList());
        }
        if (ObjectHelper.isNotBlank(statusObj)) {
            result = result.stream().filter(p -> p.getStatus().equals(Convert.toInt(statusObj))).collect(Collectors.toList());
        }
        return (List<DicDetailsEntity>) TreeHelper.filter(list, result);
    }

    /**
     * 根据字典编码获取数据字典明细简单对象列表
     *
     * @param dicCode 字典编码
     */
    public List<Simple> querySimpleByDicCode(String dicCode) {
        return dicDetailsDao.querySimpleByDicCode(dicCode);
    }

    /**
     * 根据字典编码获取数据字典对象列表
     *
     * @param dicCode 字典编码
     */
    public List<DicDetailsEntity> queryByDicCode(String dicCode) {
        return dicDetailsDao.queryByDicCode(dicCode);
    }

    /**
     * 动态加载字典明细列表
     *
     * @param id 字典明细主键
     * @return 字典明细列表
     */
    public List<DicDetailsEntity> dynamicQuery(String id) {
        return dicDetailsDao.dynamicQuery(id);
    }

    /**
     * 获取字典明细名称
     *
     * @param id 字典明细主键
     * @return 字典明细名称
     */
    public String queryNameById(String id) {
        return dicDetailsDao.queryNameById(id);
    }

    /**
     * 获取字典明细值
     *
     * @param id 字典明细主键
     * @return 字典明细值
     */
    public String queryValueById(String id) {
        return dicDetailsDao.queryValueById(id);
    }

    /**
     * 查询Tree模型列表
     */
    public List<Tree> queryTreeModelList(String dicCode, Integer status) {
        return dicDetailsDao.queryTreeModelList(dicCode, status);
    }

    /**
     * 转为节点列表
     *
     * @param modelList 模型列表
     */
    public List<TreeNode> convertToNodeList(List<DicDetailsEntity> modelList) {
        return TreeHelper.toTreeNodeList(modelList);
    }

    /**
     * 生成历史记录对象
     */
    private HistoryModel.HistoryModelBuilder buildHistory() {
        return HistoryModel.builder()
                .tableName("sys_dic_details")
                .tableCaption("系统字典明细")
                .keyName("id");
    }
}
